package purchase

import (
	mc "bbtradeByGo/model/match"
	rmc "bbtradeByGo/model/match/model"
	"bbtradeByGo/pkg/email"
	"bbtradeByGo/pkg/gredis"
	"bbtradeByGo/pkg/logging"
	"bbtradeByGo/service/match/helper"
	sal "bbtradeByGo/service/match/sale"
	"encoding/json"
	"fmt"
	"github.com/gomodule/redigo/redis"
	"math/big"
)

//PurChase 买单
func PurChase(condition *rmc.MCondition) {
	/*
	 *  1--> `买单数量` > `卖单数量` ==> 继续撮合    更新买单 移除队列中的卖单
	 *  2--> `买单数量` < `卖单数量` ==> 停止撮合    更新队列中的卖单
	 *  0--> `买单数量` = `卖单数量` ==> 停止撮合    移除队列中的卖单
	 */
	saleKey     := fmt.Sprintf("currency:match:sale:%d/%d", condition.BaseCurrencyId, condition.CurrencyId)
	purchaseKey := fmt.Sprintf("currency:match:purchase:%d/%d", condition.BaseCurrencyId, condition.CurrencyId)
	cancelKey   := fmt.Sprintf("currency:match:cancel:%d/%d", condition.BaseCurrencyId, condition.CurrencyId)

	saleList, err := redis.Values(gredis.LRange(saleKey, 0, -1))
	if err != nil {
		email.SendMail("service.match.purchase.PurChase", err.Error())
		logging.Error("service.match.purchase.PurChase err:", err)
	}

	if len(saleList) > 0 {
		for i, vs := range saleList{

			//市价交易
			var v = rmc.MCondition{}
			err = json.Unmarshal(vs.([]byte), &v)
			if err != nil {
				email.SendMail("service.match.purchase.PurChase json.Unmarshal", err.Error())
				logging.Error("service.match.purchase.PurChase json.Unmarshal err:", err)
			}
			if condition.Tradetype == 1 {
				condition.Price = v.Price
			}
			//1.买价大于卖价，进行撮合

			if condition.Price >= v.Price{
				res := PurMatch(condition, &v, purchaseKey, saleKey, cancelKey)
				if res == nil{return}
				switch res.IsContinue {
				    case 1:
					   condition = res.Purchase
					   _, err := gredis.LRem(saleKey, res.Sale, 1)
					   if err != nil {
						   email.SendMail("service.match.purchase.PurChase gredis.LRem err1", err.Error())
						   logging.Error("service.match.purchase.PurChase gredis.LRem err1:", err)
					   }
					   //买单不够成交
					   if i == len(saleList) - 1 {
						   //如果市价要成交的数量大于目前限价单的数量，取消市价单
						   //console.log(`卖单数量不够-->\n${JSON.stringify(order)}`);
						   if condition.Tradetype == 1 {
							  mc.OrderCancel(condition)
						   }else {
							  //限价单放入到队列中
							  RePush(condition, purchaseKey)
						   }
					   }
				    case 2:
					   //不能直接删除，防止lrem数据后，序号改变，需要重新遍历一遍
					   _, err := gredis.LRem(saleKey, v, 1)
						if err != nil {
							email.SendMail("service.match.purchase.PurChase gredis.LRem err2", err.Error())
							logging.Error("service.match.purchase PurChase gredis.LRem err2:", err)
						}
					   gredis.LPush(saleKey, res.Sale)
				    case 3:
					   //买单撮合失败（常出现在市价交易情况，余额不够进行市价交易），自动取消订单
					   mc.OrderCancel(condition)
				    case 0:
					   _, err := gredis.LRem(saleKey, res.Sale, 1)
						if err != nil {
							email.SendMail("service.match.purchase.PurChase gredis.LRem err3", err.Error())
							logging.Error("service.match.purchase PurChase gredis.LRem err3:", err)
						}
				}
				if res.IsContinue != 1{return}
			}else {
				//2.把买单放入买单集合
				RePush(condition, purchaseKey)
				return
			}
		}
	}else {
		//没有足够的卖单
		//如果是市价交易单，取消订单
		if condition.Tradetype == 1 {
			mc.OrderCancel(condition)
		}else {

			RePush(condition, purchaseKey)
		}
	}
}

//PurMatch 撮合订单
func PurMatch(purchase, sale *rmc.MCondition, purchaseKey, saleKey, cancelKey string) *rmc.MakeUp{
	 //获取基础币的买入和卖出手续费
     fees, err :=mc.FeeGet(sale.CurrencyId, sale.BaseCurrencyId)
     if err != nil {
		 email.SendMail("service.match.purchase.PurMatch FeeGet", err.Error())
		 logging.Error("service.match.purchase.PurMatch FeeGet err:", err)
	 }
     if fees == nil{return nil}
     sellFee := fees.SellFee
     buyFee  := fees.BuyFee

	//卖单是否取消
	isOK := PurIsCancel(cancelKey, sale)
	if isOK {
		 return &rmc.MakeUp{
		 	IsContinue: 1,
		 	Purchase: purchase,
		 	Sale: sale,
		 }
	 }

     var isContinue int
     //撮合买单，按照卖单价成交
     if purchase.Surplus > sale.Surplus {
     	purchase = RePurChaseGt(purchase, sale, sellFee, buyFee)
     	isContinue = 1 //
	 }else if purchase.Surplus < sale.Surplus {
        sale = ReSaleGt(sale, purchase, sellFee, buyFee)
        isContinue = 2
	 }else {
	 	RePsEq(purchase, sale, sellFee, buyFee)
	 	isContinue = 0
	 }
     return &rmc.MakeUp{
     	IsContinue: isContinue,
     	Purchase: purchase,
     	Sale: sale,
	 }
}

//PurIsCancel 订单是否被取消
func PurIsCancel(cancelKey string, sale *rmc.MCondition) bool{
	cancelList, err := redis.Values(gredis.LRange(cancelKey, 0, -1))
	if err != nil {
		email.SendMail("service.match.purchase.PurIsCancel err1", err.Error())
		logging.Error("service.match.purchase.PurIsCancel err1:", err)
	}
	if sal.IndexOf(sale.Id, cancelList) > -1 {
		//移除取消订单队列
		_, err := redis.Int(gredis.LRem(cancelKey, sale.Id, 1))
		if err != nil {
			email.SendMail("service.match.purchase.PurIsCancel err2", err.Error())
			logging.Error("service.match.purchase.PurIsCancel err2:", err)
		}
		return true
	}
	return false
}

//RePush 将买单放入集合中
func RePush(condition *rmc.MCondition, purchaseKey string) {
	purchaseList, err := redis.Values(gredis.LRange(purchaseKey, 0, -1))
	if err != nil {
		email.SendMail("service.match.purchase.RePush err1", err.Error())
		logging.Error("service.match.purchase RePush err1:", err)
	}
    fmt.Println(len(purchaseList))
	if len(purchaseList) > 0 {
		for i, v := range purchaseList{
			s := rmc.MCondition{}
			err = json.Unmarshal(v.([]byte), &s)
			if err != nil {
				email.SendMail("service.match.purchase.RePush err2", err.Error())
				logging.Error("service.match.purchase.RePush err2:", err)
			}
			//价格高的放前面
			if condition.Price > s.Price {
				gredis.LInsert(purchaseKey, "before", s, condition)
				return
			}else if i == len(purchaseList) - 1 {
				gredis.RPush(purchaseKey, condition)
			}
		}

	}else {
		gredis.RPush(purchaseKey, condition)
	}
}

//PurChaseGt 买入大于卖出，剩余买入
func RePurChaseGt(purchase, sale *rmc.MCondition, sellFee, buyFee float64) *rmc.MCondition{
	taker := 1
	price  := sale.Price
	//可被撮合数量
	number := sale.Surplus

	helper.DoMatch(purchase, sale, sellFee, buyFee, number, price, taker)

	purchaseTrademoney     := big.NewFloat(purchase.Trademoney)
	purchaseSurplus        := big.NewFloat(purchase.Surplus)
	BigNumber      := big.NewFloat(number)
	BigPrice := big.NewFloat(price)
	logging.Info("service.match.purchase.RePurChaseGt purchaseTrademoney:", purchaseTrademoney)
	logging.Info("service.match.purchase.RePurChaseGt purchaseSurplus:", purchaseSurplus)
	logging.Info("service.match.purchase.RePurChaseGt BigNumber:", BigNumber)
	logging.Info("service.match.purchase.RePurChaseGt BigPrice:", BigPrice)


	mulResult := BigNumber.Mul(BigPrice, BigNumber)

	logging.Info("service.match.purchase.RePurChaseGt mulResult:", mulResult)


	purchase.Trademoney, _ = mulResult.Add(mulResult, purchaseTrademoney).Float64()
	logging.Info("service.match.purchase.RePurChaseGt purchase.Trademoney:", purchase.Trademoney)

	purchase.Surplus, _    = purchaseSurplus.Sub(purchaseSurplus, big.NewFloat(number)).Float64()
	logging.Info("service.match.purchase.RePurChaseGt purchase.Surplus:", purchase.Surplus)
	// 1->部分成交
	purchase.OrderStatus = 1
	return purchase
}

//ReSaleGt 卖出大于买入，剩余卖出
func ReSaleGt(sale, purchase *rmc.MCondition, sellFee, buyFee float64) *rmc.MCondition{
	taker := 1
	price  := sale.Price
	//可被撮合数量
	number := purchase.Surplus


	helper.DoMatch(purchase, sale, sellFee, buyFee, number, price, taker)

	saleTrademoney     := big.NewFloat(sale.Trademoney)
	saleSurplus        := big.NewFloat(sale.Surplus)
	num      := big.NewFloat(number)
	pri      := big.NewFloat(price)

	logging.Info("service.match.purchase.ReSaleGt saleTrademoney:", saleTrademoney)
	logging.Info("service.match.purchase.ReSaleGt saleSurplus:", saleSurplus)
	logging.Info("service.match.purchase.ReSaleGt num:", num)
	logging.Info("service.match.purchase.ReSaleGt pri:", pri)




	mulResult := num.Mul(num, pri)
	logging.Info("service.match.purchase.ReSaleGt mulResult:", mulResult)

	sale.Trademoney, _ = mulResult.Add(mulResult, saleTrademoney).Float64()
	sale.Surplus, _    = saleSurplus.Sub(saleSurplus, big.NewFloat(number)).Float64()

	logging.Info("service.match.purchase.ReSaleGt sale.Trademoney:", sale.Trademoney)
	logging.Info("service.match.purchase.ReSaleGt sale.Surplus:", sale.Surplus)



	// 1->部分成交
	sale.OrderStatus = 1
	return sale
}

//RePsEq 买入等于卖出
func RePsEq(purchase, sale *rmc.MCondition, sellFee, buyFee float64){
	taker := 1
	price  := sale.Price
	//可被撮合数量
	number := purchase.Surplus

	helper.DoMatch(purchase, sale, sellFee, buyFee, number, price, taker)
}


